<template>
  <div class="qm-dept-cascader">
    <!-- 输入框 -->
    <div class="list">
      <a href="#" class="item-link" @click="show = true">
        <div class="item-content">
          <div class="item-inner">
            <div class="item-title">{{label}}</div>
            <div class="item-after">{{fieldValue}}</div>
          </div>
        </div>
      </a>
    </div>
    <!-- 弹出层 -->
    <van-popup v-model="show" round position="bottom">
      <!-- 级联选择器 -->
      <div class="qm-cascader">
        <!-- 级联头部 -->
        <div class="qm-cascader__header">
          <h2 class="qm-cascader__title">{{label}}</h2>
          <i class="van-icon van-icon-cross van-cascader__close-icon" @click="show = false"></i>
        </div>
        <!-- 级联主体 -->
        <van-tabs v-model="active">
          <van-tab
            v-for="({text, options}, i) in tabs"
            :key="`${text}-${i}`"
            :title-class="{'qm-cascader__tab': true, 'qm-cascader__tab--unselected': !multiple && text === '请选择'}"
            :title="text"
          >
            <ul class="qm-cascader__options">
              <li
                v-for="(option, idx) in options"
                :key="`${option.text}-${idx}`"
                class="qm-cascader__option"
                :class="{'qm-cascader__option--selected': !multiple && isSelect(option.self)}"
                @click="() => onClickItem(option, i, idx)">
                <span class="qm-cascader__option__left">
                  <!-- 复选框，多选时显示 -->
                  <van-checkbox
                    v-if="multiple"
                    v-model:value="option.self.selected"
                    @click.native.stop
                    @change="(checked) => handleCheck(checked, option, i, idx)">
                  </van-checkbox>
                  {{option.text}}
                </span>
                <van-icon v-if="!multiple && selectedStack.indexOf(option.self) !== -1" name="success" class="qm-cascader__selected-icon" />
                <van-icon v-if="multiple && option.isHasChild" name="arrow" />
              </li>
            </ul>
          </van-tab>
        </van-tabs>
        <div class="tags__wrapper">
          <van-tag
            v-for="(tag, i) in selectedStack"
            :key="tag.value"
            closeable
            size="medium"
            type="primary"
            @close="() => onTagClose(tag)">
            {{tag.text}}
          </van-tag>
        </div>
      </div>
    </van-popup>
  </div>
</template>

<script>
import { Tabs, Tab, Popup, Icon, Checkbox, Tag } from  "vant";
export default {
  name: "qm-dept-cascader",
  components: {
    [Tabs.name]: Tabs,
    [Tab.name]: Tab,
    [Popup.name]: Popup,
    [Icon.name]: Icon,
    [Checkbox.name]: Checkbox,
    [Tag.name]: Tag
  },
  model: {
    prop: "value",
    event: "change"
  },
  props: {
    value: {
      type: Array,
      default: () => []
    },
    label: {
      type: String,
      default: "部门选择"
    },
    multiple: {
      type: Boolean,
      default: false
    },
    // [
    //   {
    //     text: "研发部",
    //     value: "0",
    //     children: [
    //       { text: "研发部-子部门1", value: "0-1", children: [{ text: "研发部-子部门1-1", value: "0-1-1" }] },
    //       { text: "研发部-子部门2", value: "0-2" }
    //     ],
    //   },
    //   {
    //     text: "综合管理部",
    //     value: "1",
    //     children: [
    //       { text: "综合管理部-子部门1", value: "1-1" },
    //       { text: "综合管理部-子部门2", value: "1-2" }
    //     ],
    //   },
    //   {
    //     text: "项目管理部",
    //     value: "2"
    //   }
    // ]
    options: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      show: false, // 弹出层显示与隐藏
      fieldValue: "", // 输入框显示值
      tabs: [], // 级联tab栏
      active: 0, // tab栏激活项
      selected: [],
      optData: [], // 复制options，增加selected属性
      selectedStack: [],
      parentSelStack: [],
      isClose: false,
      isHandleChecked: false
    };
  },
  methods: {
    // 初始化数据
    initData() {
      this.optData = this.initOptData(this.options);
      this.initTabs();
    },
    // 初始化tabs
    initTabs() {
      const options = this.optData.map((option, i) => ({
        self: option,
        text: option.text,
        selected: false,
        isHasChild: !!(option.children?.length)
      })
      );
      this.tabs = [{ text: "请选择", active: -1, options }];
    },
    // 初始化options拷贝数据，增加selected属性，存储多选框选中状态
    initOptData(options, text = "") {
      return options.map(option => {
        const completeText = !text ? option.text : text.split(" / ").concat(option.text).join(" / "); 
        const children = option.children?.length ? this.initOptData(option.children, completeText) : [];
        return Object.assign({}, option, { selected: false, children, completeText});
      })
    },
    // 点击选项
    onClickItem(option, i, idx) {
      if (this.multiple) {
        // 多选
        // this.handleMulSel(option, i);
      } else {
        // 单选
        this.handleRadioSel(option, i, idx);
      }
      this.handleTabs(option.self, i) && this.$nextTick(() => {
        this.active++;
      })
    },
    // 多选
    handleMulSel({ text }, i) {},
    // 单选
    handleRadioSel({ text, self }, i, idx) {
      const tab = this.tabs[i];
      tab.text = text; // 赋值选中文本
      tab.options.forEach((option, j) => {
        option.selected = Boolean(j === idx);
        option.self.selected = Boolean(j === idx);
      });
      this.parentSelStack.splice(0, this.parentSelStack.length);
      this.selected.splice(0, this.selected.length, self.completeText);
      this.selectedStack.splice(0, this.selectedStack.length, self);
      for (let j = 0; j < i; j++) {
        const options = this.tabs[j].options;
        const option = options.find(option => option.selected);
        // this.selected.push(option.self.completeText);
        this.parentSelStack.push(option.self);
      }
    },
    // 初始化tabs第一项后面的数据，对应options中的children
    /**
     * 
     * @param {*} pos pos对应数据项在options中的位置，采用-连接。
     * @param {*} i 数据在tabs中的位置
     */
    handleTabs(self, i) {
      let children = self?.children;
      let isHasChild = false;
      this.tabs.splice(i + 1, this.tabs.length - i - 1); // 清除点击tab后面的数据项
      // 判断children是否存在
      if (children?.length) {
        isHasChild = true;
        this.tabs.push({
          text: "请选择",
          active: -1,
          options: children.map((item, j) => ({
            self: item,
            text: item.text,
            selected: this.multiple ? item.selected : false,
            isHasChild: !!(item.children && item.children.length)
          }))
        })
      }

      return isHasChild;
    },
    // 拼接input展示文本
    splicingText() {
      this.fieldValue = this.selected.join(" ");
    },
    // 点击复选框
    handleCheck(checked, option, i) {
      if (this.isClose) {
        this.isClose = false;
        return;
      }
      if (this.isHandleChecked) return;
      this.isHandleChecked = true;
      if (checked) {
        this.selected.push(option.self.completeText);
        this.selectedStack.push(option.self);
      } else {
        this.selected.splice(this.selected.indexOf(option.self.completeText), 1);
        this.selectedStack.splice(this.selectedStack.indexOf(option.self), 1);
      }
      if (option.self.children?.length) {
        this.handleChildrenSel(option.self.children, checked);
      }
      this.handleTabs(option.self, i) && this.$nextTick(() => {
        this.active++;
      }); 
      Promise.resolve().then(() => this.isHandleChecked = false);
    },
    // 点击复选框选中所有子级
    handleChildrenSel(children, checked) {
      for (let i = 0; i < children.length; i++) {
        let item = children[i];
        let completeText = children[i].completeText;
        if (checked) {
          this.selected.indexOf(completeText) === -1 && this.selected.push(completeText);
          this.selectedStack.indexOf(children[i]) === -1 && this.selectedStack.push(children[i]);
        } else {
          this.selected.splice(this.selected.indexOf(completeText), 1);
          this.selectedStack.splice(this.selectedStack.indexOf(children[i]), 1);
        }
        item.selected !== checked && (item.selected = checked);
        if (item.children?.length) {
          this.handleChildrenSel(item.children, checked)
        }
      }
    },
    onTagClose(option) {
      this.isClose = true;
      if (this.multiple) {
        option.selected = false;
      } else {
        this.handleChildrenSel(this.optData, false);
      }

      this.selectedStack.splice(this.selectedStack.indexOf(option), 1);
      this.selected.splice(this.selected.indexOf(option.completeText), 1);
    },
    isSelect(self) {
      return this.selectedStack.indexOf(self) !== -1 || this.childIsSelect(self.children || []);
    },
    childIsSelect(children) {
      let isSelected = false;
      for (let i = 0; i < children.length; i++) {
        if (this.selectedStack.indexOf(children[i]) !== -1 || (children[i].children?.length && this.childIsSelect(children[i].children))) {
          isSelected = true;
          break;
        }
      }
      return isSelected;
    }
  },
  watch: {
    options: {
      immediate: true,
      handler() {
        this.initData();
      }
    },
    multiple() {
      this.parentSelStack = [];
      this.selected = [];
      this.selectedStack = [];
    },
    selected() {
      this.splicingText();
    },
    selectedStack(selOptions) {
      let value = selOptions.map(item => item.value);
      if (!this.multiple) {
        value.unshift(...this.parentSelStack.map(item => item.value));
      }
      this.$emit("change", value);
    }
  }
}
</script>

<style lang="less" scoped>
::v-deep {
  .van-cell::after {
    border-bottom: none;
  }

  .van-tab {
    flex: none;
    padding: 0 10px;
  }

  .qm-cascader__tab {
    color: #323233;
    font-weight: 500;
  }
  .qm-cascader__tab--unselected {
    color: #969799;
    font-weight: normal;
  }

  .van-tabs__nav {
    padding-right: 6px;
    padding-left: 6px;
  }

  .item-after {
    max-width: 70%;
    overflow: hidden;
    text-overflow: ellipsis;
    position: relative;
    display: block;
  }

  .list {
    margin: 0;
  }
}

.qm-cascader__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 48px;
  padding: 0 16px;
}
.qm-cascader__title {
  font-weight: 500;
  font-size: 16px;
  line-height: 20px;
}
.qm-cascader__options {
  box-sizing: border-box;
  height: 264px;
  padding-top: 6px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.qm-cascader__option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px;
  font-size: 14px;
  line-height: 20px;
}
.qm-cascader__option--selected {
  color: #ee0a24;
  font-weight: 500;
}

.qm-cascader__selected-icon {
  font-size: 18px;
}

.qm-cascader__option__left {
  display: flex;
  align-items: center;

  .van-checkbox {
    margin-right: 4px;
  }
}

.tags__wrapper {
  padding: 10px 16px;
  height: 120px;
  overflow: auto;

  .van-tag {
    margin: 2px 0 2px 6px;
  }
}
</style>